home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / mail / db.1.85.tar.gz / db.1.85.tar / db.1.85 / mpool / mpool.libtp < prev    next >
Text File  |  1994-07-13  |  17KB  |  747 lines

  1. /******************************************************************************
  2.  
  3. VERSION $Id: buf.c,v 1.26 92/01/09 09:15:26 margo Exp $
  4. PACKAGE:     User Level Shared Memory Manager
  5.  
  6. DESCRIPTION:     
  7.     This package provides a buffer pool interface implemented as
  8.     a collection of file pages mapped into shared memory.
  9.  
  10.     Based on Mark's buffer manager
  11.  
  12. ROUTINES: 
  13.     External
  14.     buf_alloc
  15.     buf_flags
  16.     buf_get
  17.     buf_init
  18.     buf_last
  19.     buf_open
  20.     buf_pin
  21.     buf_sync
  22.     buf_unpin
  23.     Internal
  24.     bf_assign_buf
  25.     bf_fid_to_fd
  26.     bf_newbuf
  27.     bf_put_page
  28.     
  29.  
  30. ******************************************************************************/
  31. #include    <sys/types.h>
  32. #include    <assert.h>
  33. #include    <sys/file.h>
  34. #include    <sys/stat.h>
  35. #include    <stdio.h>
  36. #include    <errno.h>
  37. #include    "list.h"
  38. #include    "user.h"
  39. #include    "txn_sys.h"
  40. #include    "buf.h"
  41. #include    "semkeys.h"
  42. #include    "error.h"
  43.  
  44. /*
  45.     we need to translate between some type of file id that the user 
  46.     process passes and a file descriptor.  For now, it's a nop.
  47. */
  48. #define GET_MASTER      get_sem ( buf_spinlock )
  49. #define RELEASE_MASTER  release_sem ( buf_spinlock )
  50.  
  51. #define    LRUID    *buf_lru
  52. #define    LRUP    (bufhdr_table+*buf_lru)
  53. #define    MRU    bufhdr_table[*buf_lru].lru.prev
  54.  
  55. /* Global indicator that you have started reusing buffers */
  56. int    do_statistics = 0;
  57. /*
  58.     Process Statics (pointers into shared memory)
  59. */
  60. static    BUF_T    *buf_table = 0;
  61. static    BUFHDR_T    *bufhdr_table;
  62. static    int    *buf_hash_table;
  63. static    int    *buf_lru;        /* LRU is the free list */
  64. static    int    buf_spinlock;
  65. static    FINFO_T    *buf_fids;
  66. static    int    *buf_sp;        /* Pointer to string free space */
  67. static    char    *buf_strings;
  68.  
  69. /* Process Local FID->FD table */
  70. static    int    fds[NUM_FILE_ENTRIES];
  71.  
  72. /* Static routines */
  73. static    BUFHDR_T    *bf_assign_buf();
  74. static    int        bf_fid_to_fd();
  75. static    BUFHDR_T    *bf_newbuf();
  76. static    int        bf_put_page();
  77.  
  78. /*
  79.     Return  0 on success
  80.         1 on failure
  81. */
  82. extern int
  83. buf_init ( )
  84. {
  85.     ADDR_T    buf_region;
  86.     BUFHDR_T    *bhp;
  87.     int        i;
  88.     int        ref_count;
  89.     int        *spinlockp;
  90.  
  91.     /*
  92.     Initialize Process local structures
  93.     */
  94.     for ( i = 0; i < NUM_FILE_ENTRIES; i++ ) {
  95.     fds[i] = -1;
  96.     }
  97.  
  98.     buf_region = attach_region ( BUF_REGION_NAME, BUF_REGION_NUM,
  99.                  BUF_REGION_SIZE, &ref_count );
  100.     if ( !buf_region ) {
  101.     return (1);
  102.     }
  103.     error_log3 ( "Buf Region: ADDR: %d ID: %d SIZE: %d\n", buf_region,
  104.             BUF_REGION_NUM, BUF_REGION_SIZE );
  105.  
  106.     buf_table = (BUF_T *)buf_region;
  107.     bufhdr_table = (BUFHDR_T *)(buf_table + NUM_BUFS);
  108.     buf_hash_table = (int *)(bufhdr_table + NUM_BUFS);
  109.     buf_lru = buf_hash_table + NUMTABLE_ENTRIES;
  110.     spinlockp = buf_lru + 1;
  111.     buf_fids = (FINFO_T *)(spinlockp+1);
  112.     buf_sp = (int *)(buf_fids + NUM_FILE_ENTRIES);
  113.     buf_strings = (char *)(buf_sp + 1);
  114.  
  115.     /* Create locking spinlock (gets creating holding the lock) */
  116.     buf_spinlock = create_sem ( BUF_SPIN_NAME, BUF_SPIN_NUM, ref_count <= 1 );
  117.     if ( buf_spinlock < 0 )  {
  118.     return(1);
  119.     }
  120.     if ( ref_count <= 1 ) {
  121.     *spinlockp = buf_spinlock;
  122.  
  123.     /* Now initialize the buffer manager */
  124.  
  125.     /* 1. Free list */
  126.     *buf_lru = 0;
  127.  
  128.     /* 2. Buffer headers */
  129.     for ( i = 0, bhp = bufhdr_table; i < NUM_BUFS; bhp++, i++ ) {
  130.         bhp->lru.next = i+1;
  131.         bhp->lru.prev = i-1;
  132.         bhp->flags = 0;                /* All Flags off */
  133.         bhp->refcount = 0;
  134.         bhp->wait_proc = -1;            /* No sleepers */
  135.         LISTPE_INIT ( hash, bhp, i );        /* Hash chains */
  136.     }
  137.     bufhdr_table[0].lru.prev = NUM_BUFS-1;
  138.     bufhdr_table[NUM_BUFS-1].lru.next = 0;
  139.  
  140.     /* 3. Hash Table */
  141.     for ( i = 0; i < NUMTABLE_ENTRIES; i++ ) {
  142.         buf_hash_table[i] = NUM_BUFS;
  143.     }
  144.  
  145.     /* 4. File ID Table */
  146.     for ( i = 0; i < NUM_FILE_ENTRIES; i++ ) {
  147.         buf_fids[i].offset = -1;
  148.         buf_fids[i].npages = -1;
  149.         buf_fids[i].refcount = 0;
  150.     }
  151.  
  152.     /* 5. Free String Pointer */
  153.     *buf_sp = (FILE_NAME_LEN*NUM_FILE_ENTRIES);
  154.     if (RELEASE_MASTER) {
  155.         return(1);
  156.     }
  157.     error_log0 ( "Initialized buffer region\n" );
  158.     } 
  159.     return (0);
  160. }
  161.  
  162. extern    void
  163. buf_exit()
  164. {
  165.     int    ref;
  166.     int    i;
  167.  
  168.     /* Flush Buffer Pool on Exit */
  169.     for ( i = 0; i < NUM_FILE_ENTRIES; i++ ) {
  170.     if ( fds[i] != -1 ) {
  171.         close ( fds[i] );
  172.     }
  173.     }
  174.     if ( buf_table ) {
  175.     detach_region ( buf_table, BUF_REGION_NUM, BUF_REGION_SIZE, &ref );
  176.     }
  177.     return;
  178. }
  179.  
  180. /*
  181.     We need an empty buffer.  Find the LRU unpinned NON-Dirty page.
  182. */
  183. static BUFHDR_T    *
  184. bf_newbuf()
  185. {
  186.     int        fd;
  187.     int        lruid;
  188.     int        nbytes;
  189.     int        ndx;
  190.     BUFHDR_T    *bhp;
  191.  
  192.     lruid = LRUID;
  193.     for ( bhp = LRUP; 
  194.       bhp->flags & (BUF_PINNED|BUF_IO_IN_PROGRESS); 
  195.       bhp = LISTP_NEXTP (bufhdr_table, lru, bhp ) ) {
  196.  
  197.     if ( bhp->lru.next == lruid ) {
  198.         /* OUT OF BUFFERS */
  199.         error_log1 ( "All buffers are pinned.  %s\n",
  200.                 "Unable to grant buffer request" );
  201.         return(NULL);
  202.     }
  203.     }
  204.     /* BHP can be used */
  205.     if ( bhp->flags & BUF_DIRTY ) {
  206.     do_statistics = 1;
  207.     /* 
  208.         MIS  Check for log flushed appropriately
  209.     */
  210.     fd = bf_fid_to_fd(bhp->id.file_id);
  211.     if ( fd == -1 ) {
  212.         error_log1 ("Invalid fid %d\n", bhp->id.file_id);
  213.         return(NULL);
  214.     }
  215.     if ( bf_put_page(fd, bhp) < 0 ) {
  216.         return(NULL);
  217.     }
  218.     }
  219.     /* Update Hash Pointers */
  220.     ndx = BUF_HASH ( bhp->id.file_id, bhp->id.obj_id );
  221.     LISTP_REMOVE(bufhdr_table, hash, bhp);
  222.     if ( buf_hash_table[ndx] == (bhp-bufhdr_table) ) {
  223.     if ( bhp->hash.next != (bhp-bufhdr_table) ) {
  224.         buf_hash_table[ndx] = bhp->hash.next;
  225.     } else {
  226.         buf_hash_table[ndx] = NUM_BUFS;
  227.     }
  228.     }
  229.     INIT_BUF(bhp); 
  230.  
  231.     return(bhp);
  232. }
  233. /*
  234.     buf_alloc
  235.  
  236.     Add a page to a file and return a buffer for it.
  237.  
  238. */
  239. ADDR_T
  240. buf_alloc ( fid, new_pageno )
  241. int    fid;
  242. int    *new_pageno;
  243. {
  244.     BUFHDR_T    *bhp;
  245.     int    fd;
  246.     int    len;
  247.     int    ndx;
  248.     OBJ_T    fobj;
  249.  
  250.     if (GET_MASTER) {
  251.         return(NULL);
  252.     }
  253.     if ( buf_fids[fid].npages == -1 ) {
  254.         /* initialize npages field */
  255.         fd = bf_fid_to_fd ( fid );
  256.     }
  257.     assert (fid < NUM_FILE_ENTRIES);
  258.  
  259.     *new_pageno = buf_fids[fid].npages;
  260.     if ( *new_pageno == -1 ) {
  261.         RELEASE_MASTER;
  262.         return ( NULL );
  263.     }
  264.     buf_fids[fid].npages++;
  265.     ndx = BUF_HASH ( fid, *new_pageno );
  266.     fobj.file_id = fid;
  267.     fobj.obj_id  = *new_pageno;
  268.     bhp = bf_assign_buf ( ndx, &fobj, BF_PIN|BF_DIRTY|BF_EMPTY, &len );
  269.     if ( RELEASE_MASTER ) {
  270.         /* Memory leak */
  271.         return(NULL);
  272.     }
  273.     if ( bhp ) {
  274.         return ((ADDR_T)(buf_table+(bhp-bufhdr_table)));
  275.     } else {
  276.         return ( NULL );
  277.     }
  278. }
  279.  
  280.  
  281. /*
  282.     Buffer Flags
  283.     BF_DIRTY        Mark page as dirty
  284.     BF_EMPTY        Don't initialize page, just get buffer
  285.     BF_PIN            Retrieve with pin 
  286.  
  287. MIS
  288. Might want to add a flag that sets an LSN for this buffer is the
  289. DIRTY flag is set
  290.  
  291. Eventually, you may want a flag that indicates the I/O and lock
  292. request should be shipped off together, but not for now.
  293. */
  294. extern ADDR_T
  295. buf_get ( file_id, page_id, flags, len )
  296. int    file_id;
  297. int    page_id;
  298. u_long    flags;
  299. int    *len;        /* Number of bytes read into buffer */
  300. {
  301.     BUFHDR_T    *bhp;
  302.     int        bufid;
  303.     int        fd;
  304.     int        ndx;
  305.     int        next_bufid;
  306.     int        stat;
  307.     OBJ_T        fobj;    
  308.  
  309.     ndx = BUF_HASH ( file_id, page_id );
  310.     fobj.file_id = (long) file_id;
  311.     fobj.obj_id = (long) page_id;
  312.     if ( GET_MASTER ) {
  313.         return(NULL);
  314.     }
  315.     /*
  316.         This could be a for loop, but we lose speed
  317.         by making all the cases general purpose so we
  318.         optimize for the no-collision case. 
  319.     */
  320.     bufid = buf_hash_table[ndx]; 
  321.     if ( bufid < NUM_BUFS ) {
  322.         for ( bhp = bufhdr_table+bufid; 
  323.           !OBJ_EQ (bhp->id, fobj) || !(bhp->flags & BUF_VALID);
  324.           bhp = LISTP_NEXTP ( bufhdr_table, hash, bhp ) ) {
  325.  
  326.         if ( bhp->hash.next == bufid ) {
  327.             goto not_found;
  328.         }
  329.         }
  330. /* found */
  331.         if ( flags & BF_PIN ) {
  332.             bhp->flags |= BUF_PINNED;
  333.             bhp->refcount++;
  334. #ifdef PIN_DEBUG
  335.     fprintf(stderr, "buf_get: %X PINNED (%d)\n", 
  336.             buf_table + (bhp-bufhdr_table), bhp->refcount);
  337. #endif
  338.         }
  339.         if ( flags & BF_DIRTY ) {
  340.             bhp->flags |= BUF_DIRTY;
  341.         }
  342.  
  343.         while ( bhp->flags & BUF_IO_IN_PROGRESS ) {
  344.         /* MIS -- eventually err check here */
  345. #ifdef DEBUG
  346.         printf("About to sleep on %d (me: %d\n)\n", bhp->wait_proc,
  347.             my_txnp - txn_table);
  348. #endif
  349. #ifdef WAIT_STATS
  350.         buf_waits++;
  351. #endif
  352.         stat = proc_sleep_on ( &(bhp->wait_proc), buf_spinlock );
  353.         if ( stat ) {
  354.             /* Memory leak */
  355.             return(NULL);
  356.         }
  357.         if (!( bhp->flags & BUF_IO_IN_PROGRESS) &&
  358.             (!OBJ_EQ (bhp->id, fobj) || !(bhp->flags & BUF_VALID))) {
  359.             if (RELEASE_MASTER)
  360.                 return(NULL);
  361.             return(buf_get ( file_id, page_id, flags, len ));
  362.         }
  363.         }
  364.         MAKE_MRU( bhp );
  365.         *len = BUFSIZE;
  366.     } else {
  367. not_found:
  368.         /* If you get here, the page isn't in the hash table */
  369.         bhp = bf_assign_buf ( ndx, &fobj, flags, len );
  370.     }
  371.     /* Common code between found and not found */
  372.  
  373.     if ( bhp && bhp->flags & BUF_NEWPAGE ) {
  374.         *len = 0;
  375.     }
  376.     if (RELEASE_MASTER){
  377.         /* Memory leak */
  378.         return(NULL);
  379.     }
  380.     if ( bhp ) {
  381.         return ((ADDR_T)(buf_table+(bhp-bufhdr_table)));
  382.     } else {
  383.         return ( NULL );
  384.     }
  385. }
  386.  
  387. /*
  388.     MIS - do I want to add file links to buffer pool?
  389. */
  390. extern int
  391. buf_sync ( fid, close )
  392. int    fid;
  393. int    close;        /* should we dec refcount and possibly
  394.                invalidate all the buffers */
  395. {
  396.     int    i;
  397.     int    fd;
  398.     int    invalidate;
  399.     BUFHDR_T    *bhp;
  400.  
  401.     if ( (fd = bf_fid_to_fd ( fid )) < 0 ) {
  402.     return(1);
  403.     }
  404.     if (GET_MASTER) {
  405.     return(1);
  406.     }
  407.     invalidate = (buf_fids[fid].refcount == 1 && close);
  408.     if ( invalidate )
  409.     for ( bhp = bufhdr_table, i = 0; i < NUM_BUFS; bhp++, i++ ) {
  410.         if (bhp->id.file_id == fid) {
  411.         if ((bhp->flags & BF_DIRTY) && (bf_put_page( fd, bhp ) < 0)) {
  412.             return(1);
  413.         }
  414.         bhp->id.file_id = -1;
  415.         }
  416.     }
  417.     if (invalidate || close)
  418.     buf_fids[fid].refcount--;
  419.  
  420.     if (RELEASE_MASTER) {
  421.     return(1);
  422.     }
  423.     return(0);
  424.  
  425.  
  426. }
  427.  
  428. extern int
  429. buf_flags ( addr, set_flags, unset_flags )
  430. ADDR_T    addr;
  431. u_long    set_flags;
  432. u_long    unset_flags;
  433. {
  434.     int        bufid;
  435.     BUFHDR_T    *bhp;
  436.  
  437. #ifdef PIN_DEBUG
  438.     fprintf(stderr, "buf_flags: %X setting %s%s%s%s%s releasing %s%s%s%s%s\n",
  439.         addr, 
  440.         set_flags&BUF_DIRTY ? "DIRTY " : "", 
  441.         set_flags&BUF_VALID ? "VALID " : "", 
  442.         set_flags&BUF_PINNED ? "PINNED " : "", 
  443.         set_flags&BUF_IO_ERROR ? "IO_ERROR " : "", 
  444.         set_flags&BUF_IO_IN_PROGRESS ? "IO_IN_PROG " : "", 
  445.         set_flags&BUF_NEWPAGE ? "NEWPAGE " : "", 
  446.         unset_flags&BUF_DIRTY ? "DIRTY " : "", 
  447.         unset_flags&BUF_VALID ? "VALID " : "", 
  448.         unset_flags&BUF_PINNED ? "PINNED " : "", 
  449.         unset_flags&BUF_IO_ERROR ? "IO_ERROR " : "", 
  450.         unset_flags&BUF_IO_IN_PROGRESS ? "IO_IN_PROG " : "", 
  451.         unset_flags&BUF_NEWPAGE ? "NEWPAGE " : "" );
  452. #endif
  453.     if (!ADDR_OK(addr)) {
  454.     error_log1 ( "buf_pin: Invalid Buffer Address %x\n", addr );
  455.     return(1);
  456.     }
  457.     bufid = ((BUF_T *)addr) - buf_table;
  458.     assert ( bufid < NUM_BUFS);
  459.     bhp = &bufhdr_table[bufid];
  460.     if (GET_MASTER) {
  461.     return(1);
  462.     }
  463.     bhp->flags |= set_flags;
  464.     if ( set_flags & BUF_PINNED ) {
  465.     bhp->refcount++;
  466.     }
  467.     if ( set_flags & BUF_DIRTY ) {
  468.     unset_flags |= BUF_NEWPAGE;
  469.     }
  470.  
  471.     if ( unset_flags & BUF_PINNED ) {
  472.     bhp->refcount--;
  473.     if ( bhp->refcount ) {
  474.         /* Turn off pin bit so it doesn't get unset */
  475.         unset_flags &= ~BUF_PINNED;
  476.     }
  477.     }
  478.     bhp->flags &= ~unset_flags;
  479.     MAKE_MRU(bhp);
  480.     if (RELEASE_MASTER) {
  481.     return(1);
  482.     }
  483.     return(0);
  484. }
  485.  
  486. /*
  487.     Take a string name and produce an fid.
  488.  
  489.     returns -1 on error
  490.  
  491.     MIS -- this is a potential problem -- you keep actual names
  492.         here -- what if people run from different directories?
  493. */
  494. extern    int
  495. buf_name_lookup ( fname )
  496. char    *fname;
  497. {
  498.     int    i;
  499.     int    fid;
  500.     int    ndx;
  501.  
  502.     fid = -1;
  503.     if (GET_MASTER) {
  504.         return(-1);
  505.     }
  506.     for ( i = 0; i < NUM_FILE_ENTRIES; i++ ) {
  507.     if ( buf_fids[i].offset == -1 ) {
  508.         fid = i;
  509.     } else {
  510.         if (!strcmp (fname, buf_strings+buf_fids[i].offset)) {
  511.             if (RELEASE_MASTER) {
  512.                 return(-1);
  513.             }
  514.             buf_fids[i].refcount++;
  515.             return(i);
  516.         }
  517.     }
  518.     }
  519.     if ( fid == -1 ) {
  520.     error_log0 ( "No more file ID's\n" );
  521.     } else {
  522.     ndx = *buf_sp - strlen(fname) - 1;
  523.     if ( ndx < 0 ) {
  524.         error_log0 ( "Out of string space\n" );
  525.         fid = -1;
  526.     } else {
  527.         *buf_sp = ndx;
  528.         strcpy ( buf_strings+ndx, fname );
  529.         buf_fids[fid].offset = ndx;
  530.     }
  531.     buf_fids[fid].refcount = 1;
  532.     }
  533.     if (RELEASE_MASTER) {
  534.     return(-1);
  535.     }
  536.     return(fid);
  537. }
  538.  
  539. static    int
  540. bf_fid_to_fd ( fid ) 
  541. int    fid;
  542. {
  543.     struct stat sbuf;
  544.  
  545.     assert ( (fid < NUM_FILE_ENTRIES) && (buf_fids[fid].offset != -1) );
  546.     if ( fds[fid] != -1 ) {
  547.         return(fds[fid]);
  548.  
  549.     }
  550.     fds[fid] = open ( buf_strings+buf_fids[fid].offset, O_RDWR|O_CREAT, 
  551.               0666 );
  552.     if ( fds[fid] < 0 ) {
  553.         error_log3 ( "Error Opening File %s FID: %d FD: %d.  Errno = %d\n", 
  554.                 buf_strings+buf_fids[fid].offset, fid, fds[fid], 
  555.                 errno );
  556.         return(-1);
  557.     }
  558.     error_log3 ( "Opening File %s FID: %d FD: %d\n", 
  559.             buf_strings+buf_fids[fid].offset, fid, fds[fid] );
  560.     if ( buf_fids[fid].npages == -1 ) {
  561.         /* Initialize the npages field */
  562.         if ( fstat ( fds[fid], &sbuf ) ) {
  563.             error_log3 ( "Error Fstating %s FID: %d.  Errno = %d\n", 
  564.                 buf_strings+buf_fids[fid].offset, fid, errno );
  565.         } else {
  566.             buf_fids[fid].npages = ( sbuf.st_size / BUFSIZE );
  567.         }
  568.     }
  569.  
  570.     return ( fds[fid] );
  571. }
  572.  
  573. static int
  574. bf_put_page ( fd, bhp ) 
  575. int    fd;
  576. BUFHDR_T    *bhp;
  577. {
  578.     int    nbytes;
  579.  
  580.     assert ( (bhp-bufhdr_table) < NUM_BUFS );
  581.     if ( lseek ( fd, bhp->id.obj_id << BUFSHIFT, L_SET ) < 0 ) {
  582.         return(-1);
  583.     }
  584.     bhp->flags |= BUF_IO_IN_PROGRESS;
  585.     if (RELEASE_MASTER) {
  586.         return(-1);
  587.     }
  588.     nbytes = write(fd, buf_table[bhp-bufhdr_table], BUFSIZE);
  589.     if (GET_MASTER) {
  590.         return(-2);
  591.     }
  592.     if ( nbytes < 0 ) {
  593.         error_log1 ("Write failed with error code %d\n", errno);
  594.         return(-1);
  595.     } else if ( nbytes != BUFSIZE ) {
  596.         error_log1 ("Short write: %d bytes of %d\n", nbytes, BUFSIZE );
  597.     }
  598.     bhp->flags &= ~(BUF_DIRTY|BUF_IO_IN_PROGRESS);
  599.     return (0);
  600. }
  601.  
  602. static BUFHDR_T    *
  603. bf_assign_buf ( ndx, obj, flags, len )
  604. int    ndx;
  605. OBJ_T    *obj;
  606. u_long    flags;
  607. int    *len;        /* Number of bytes read */
  608. {
  609.     BUFHDR_T    *bhp;
  610.     int        fd;
  611.  
  612.     assert ( obj->file_id < NUM_FILE_ENTRIES );
  613.     bhp = bf_newbuf();
  614.     if ( !bhp ) {
  615.     return(NULL);
  616.     }
  617.     OBJ_ASSIGN ( (*obj), bhp->id );
  618.     if ( buf_hash_table[ndx] >= NUM_BUFS ) {
  619.     buf_hash_table[ndx] = bhp-bufhdr_table;
  620.     } else {
  621.     LISTPE_INSERT ( bufhdr_table, hash, bhp, buf_hash_table[ndx] );
  622.     }
  623.  
  624.     bhp->flags |= BUF_VALID;
  625.     if ( flags & BF_PIN ) {
  626.     bhp->flags |= BUF_PINNED;
  627.     bhp->refcount++;
  628. #ifdef PIN_DEBUG
  629.     fprintf(stderr, "bf_assign_buf: %X PINNED (%d)\n", 
  630.         buf_table + (bhp-bufhdr_table), bhp->refcount);
  631. #endif
  632.     }
  633.     fd = bf_fid_to_fd(obj->file_id);
  634.     if ( fd == -1 ) {
  635.     error_log1 ("Invalid fid %d\n", obj->file_id);
  636.     bhp->flags |= ~BUF_IO_ERROR;
  637.     return(NULL);
  638.     }
  639.     if ( obj->obj_id >= buf_fids[obj->file_id].npages) {
  640.     buf_fids[obj->file_id].npages = obj->obj_id+1;
  641.     *len = 0;
  642.     } else if ( flags & BF_EMPTY ) {
  643.     *len = 0;
  644.     } else {
  645.     bhp->flags |= BUF_IO_IN_PROGRESS;
  646.     if (RELEASE_MASTER) {
  647.         return(NULL);
  648.     }
  649.     if ( lseek ( fd, obj->obj_id << BUFSHIFT, L_SET ) < -1 ) {
  650.         error_log2 ("Unable to perform seek on file: %d  to page %d",
  651.             obj->file_id, obj->obj_id );
  652.         bhp->flags &= ~BUF_IO_IN_PROGRESS;
  653.         bhp->flags |= ~BUF_IO_ERROR;
  654.         return(NULL);
  655.     }
  656.     *len = read(fd, buf_table[bhp-bufhdr_table], BUFSIZE);
  657.     if ( *len < 0 ) {
  658.         error_log2 ("Unable to perform read on file: %d  to page %d",
  659.             obj->file_id, obj->obj_id );
  660.         bhp->flags &= ~BUF_IO_IN_PROGRESS;
  661.         bhp->flags |= ~BUF_IO_ERROR;
  662.         return(NULL);
  663.     } 
  664.     if (GET_MASTER) {
  665.         return(NULL);
  666.     }
  667.     bhp->flags &= ~BUF_IO_IN_PROGRESS;
  668.     if ( bhp->wait_proc != -1 ) {
  669.         /* wake up waiter and anyone waiting on it */
  670. #ifdef DEBUG
  671.         printf("Waking transaction %d due to completed I/O\n", 
  672.         bhp->wait_proc);
  673. #endif
  674.         proc_wake_id ( bhp->wait_proc );
  675.         bhp->wait_proc = -1;
  676.     }
  677.     MAKE_MRU(bhp);
  678.     }
  679.  
  680.     if ( flags & BF_DIRTY ) {
  681.     bhp->flags |= BUF_DIRTY;
  682.     } else if ( *len < BUFSIZE ) {
  683.     bhp->flags |= BUF_NEWPAGE;
  684.     }
  685.     return ( bhp );
  686. }
  687.  
  688. int
  689. buf_last ( fid )
  690. int    fid;
  691. {
  692.     int    val;
  693.  
  694.     if (GET_MASTER) {
  695.         return(-1);
  696.     }
  697.     assert ( fid < NUM_FILE_ENTRIES );
  698.     if ( buf_fids[fid].npages == -1 ) {
  699.         /* initialize npages field */
  700.         (void) bf_fid_to_fd ( fid );
  701.     }
  702.     val = buf_fids[fid].npages;    
  703.     if ( val ) {
  704.         val--;            /* Convert to page number */
  705.     }
  706.     if (RELEASE_MASTER) {
  707.         return(-1);
  708.     }
  709.     return(val);
  710. }
  711.  
  712. #ifdef DEBUG
  713. extern void
  714. buf_dump ( id, all )
  715. int    id;
  716. int    all;
  717. {
  718.     int i;
  719.     BUFHDR_T    *bhp;
  720.  
  721.     printf ( "LRU + %d\n", *buf_lru );
  722.     if ( all ) {
  723.         printf("ID\tFID\tPID\tLNEXT\tLPREV\tHNEXT\tHPREV\tSLEEP\tFLAG\tREFS\n");
  724.         for ( bhp = bufhdr_table, i = 0; i < NUM_BUFS; bhp++, i++ ) {
  725.             printf ( "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%x\t%d\n", i,
  726.             bhp->id.file_id, bhp->id.obj_id,
  727.             bhp->lru.next, bhp->lru.prev,
  728.             bhp->hash.next, bhp->hash.prev,
  729.             bhp->wait_proc, bhp->flags, bhp->refcount );
  730.         }
  731.     } else {
  732.         if ( id >= NUM_BUFS ) {
  733.             printf ( "Buffer ID (%d) too high\n", id );
  734.             return;
  735.         }
  736.         bhp = bufhdr_table+id;
  737.         printf ( "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%x\t%d\n", i,
  738.             bhp->id.file_id, bhp->id.obj_id,
  739.             bhp->lru.next, bhp->lru.prev,
  740.             bhp->hash.next, bhp->hash.prev,
  741.             bhp->wait_proc, bhp->flags, bhp->refcount );
  742.     }
  743.     return;
  744. }
  745. #endif
  746.  
  747.